﻿using NUnit.Framework;
using Sasa.QualityTools.CodeAnalysis.Core.Models;
using Sasa.QualityTools.CodeAnalysis.MSBuild.Tests.Unit.Instruments;
using System;
using System.IO;

namespace Sasa.QualityTools.CodeAnalysis.MSBuild.Tests.Unit
{
    [TestFixture]
    [RequiresSTA]
    public class PerformCodeInspectionTest
    {
        private static readonly string SolutionDir = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "..", ".."));

        private static readonly string ProjectDir = Path.Combine(SolutionDir, "TestTarget");

        private static readonly string TargetPath = Path.Combine(Environment.CurrentDirectory.Replace(Path.Combine(SolutionDir, "MSBuild.Tests.Unit"), ProjectDir), "TestTarget.dll");

        private static readonly string ReportPath = Path.Combine(Path.GetDirectoryName(TargetPath), Core.Constants.CodeAnalysisReportFileName);

        private static readonly string ResourceDir = Path.Combine(Environment.CurrentDirectory, "Resources", "PerformCodeInspection");

        private static readonly string TaskName = "PerformCodeInspection";


        [Test]
        public void ExecuteShouldFailWhenTargetPathIsNotSpecified()
        {
            var taskParameter = String.Format("SolutionDir='{0}' ProjectDir='{1}' References='dummy'", SolutionDir, ProjectDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);
            Assert.IsFalse(result.Success);
        }

        [Test]
        public void ExecuteShouldFailWhenProjectDirIsNotSpecified()
        {
            var taskParameter = String.Format("TargetPath='{0}' SolutionDir='{1}' References='dummy'", TargetPath, SolutionDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);
            Assert.IsFalse(result.Success);
        }

        [Test]
        public void ExecuteShouldFailWhenSolutionDirIsNotFound()
        {
            var taskParameter = String.Format("TargetPath='{0}' ProjectDir='C:\\' References='dummy'", TargetPath, SolutionDir, ProjectDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);
            Assert.IsFalse(result.Success);
        }

        [Test]
        public void ExecuteShouldFailWhenReferencesIsNotSpecified()
        {
            var taskParameter = String.Format("TargetPath='{0}' SolutionDir='{1}' ProjectDir='{2}'", TargetPath, SolutionDir, ProjectDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);
            Assert.IsFalse(result.Success);
        }

        [Test]
        public void ExecuteShouldFailWhenCodeInspectionFailed()
        {
            var projectDir = Path.Combine(SolutionDir, "TestTarget.ReferenceError");
            var targetPath = Path.Combine(Environment.CurrentDirectory.Replace(Path.Combine(SolutionDir, "MSBuild.Tests.Unit"), ProjectDir), "TestTarget.ReferenceError.dll");
            var reference = GetType().Assembly.Location;
            var taskParameter = String.Format("TargetPath='{0}' SolutionDir='{1}' ProjectDir='{2}' References='{3}'", targetPath, SolutionDir, projectDir, reference);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);
            Assert.IsFalse(result.Success);
        }

        [Test]
        public void ExecuteShouldFailWhenFxCopCndReturnsBreakBuildWarning()
        {
            var dir = Path.Combine(ProjectDir, Core.Constants.CodeAnalysisConfigurationDirName);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            File.Copy(Path.Combine(ResourceDir, Core.Constants.CodeAnalysisConfigurationFileName), Path.Combine(dir, Core.Constants.CodeAnalysisConfigurationFileName));
            File.Copy(Path.Combine(ResourceDir, "Custom.ruleset"), Path.Combine(dir, "Custom.ruleset"));

            try
            {
                var taskParameter = String.Format("TargetPath='{0}' SolutionDir='{1}' ProjectDir='{2}' References='dummy'", TargetPath, SolutionDir, ProjectDir);
                var runner = new MSBuildTaskRunner();
                var result = runner.Run(TaskName, taskParameter);

                Assert.IsFalse(result.Success);
            }
            finally
            {
                Directory.Delete(dir, true);
            }
        }

        [Test]
        public void ExecuteShouldFailWhenFxCopCmdPathIsNotValid()
        {
            var taskParameter = String.Format("FxCopCmdPath='notexist.exe' TargetPath='{0}' SolutionDir='{1}' ProjectDir='{2}' References='dummy'", TargetPath, SolutionDir, ProjectDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);
            Assert.IsFalse(result.Success);
        }

        [Test]
        public void ExecuteShouldPerformCodeInspection()
        {
            if (File.Exists(ReportPath))
            {
                File.Delete(ReportPath);
            }

            var taskParameter = String.Format("TargetPath='{0}' SolutionDir='{1}' ProjectDir='{2}' References='dummy'", TargetPath, SolutionDir, ProjectDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);

            Assert.IsTrue(result.Success);

            var report = new FxCopReport();
            report.Load(ReportPath);
            Assert.AreEqual(19, report.Problems.Count);
            Assert.AreEqual(13, report.Rules.Count);
            Assert.AreEqual(0, report.Errors.Count);
        }

        [Test]
        public void ExecuteShouldPerformCodeInspectionWhenSolutionDirProbeSucceeded()
        {
            if (File.Exists(ReportPath))
            {
                File.Delete(ReportPath);
            }

            var taskParameter = String.Format("TargetPath='{0}' ProjectDir='{1}' References='dummy'", TargetPath, ProjectDir);
            var runner = new MSBuildTaskRunner();
            var result = runner.Run(TaskName, taskParameter);

            Assert.IsTrue(result.Success);

            var report = new FxCopReport();
            report.Load(ReportPath);
            Assert.AreEqual(19, report.Problems.Count);
            Assert.AreEqual(13, report.Rules.Count);
            Assert.AreEqual(0, report.Errors.Count);
        }
    }
}
